Release 10.1A: OpenEdge Development:
Progress Dynamics Advanced Development


Identifying the level of an attribute value

Because the attribute value can be associated with any of three other tables (gsc_object_type, ryc_smartobject, or ryc_object_instance), it is necessary to identify which of the tables the value relates to. This tells us whether this is:

The ryc_attribute_value table contains an object_type_obj object ID field, a smartobject_obj object ID, and an object_instance_obj object ID. There is also an object ID field for the container_smartobject_obj if this value is for an object_instance. Figure 8–4 is a diagram from the database model and illustrates how these fields relate the attribute_value to the object_type, smartobject, and object_instance tables.

Figure 8–4: Attribute value and table relationships

The following sections describe the different ways these fields can be used:

Defining attributes at the object type level

When the framework creates entries for attributes of an object type, the object_type_obj points to the object Type class, and the SmartObject and instance object IDs are set to 0.

To illustrate, Figure 8–5 shows an example diagram for the NavigationSourceEvents attribute, defined for the Query class. A Query object, such as an SDO, subscribes to various events in its Navigation-Source, and this attribute lists those events. These are defined at the class level and normally not changed by individual objects built using the class. So we can expect that there will be a single ryc_attribute_value record in the Repository database for this attribute for the Query class, but no other records for specific SDOs in the application. Figure 8–5 shows the relationships for the attribute_value record in this case.

Figure 8–5: NavigationSourceEvents attribute

Here you see that only the object type relationship is defined for attribute values that are default values for a class.

Defining attribute values at the object master level

When the framework creates entries in the table for an object master, it populates the object_type_obj field to avoid having 0 in the key. It also sets the smartobject_obj to point to the ryc_smartobject record that defines the object.

To illustrate this case, Figure 8–6 shows the relationships for the MinHeight attribute of the dynamic viewer customerviewv. This attribute sets an object’s initial height and is defined when the object is created. Because viewers come in all different sizes, this attribute is defined at the master level, along with the MinWidth attribute, to define the size of the viewer. You can see this attribute in the dynamic property sheet for the viewer when you edit it in the AppBuilder.

Figure 8–6: Attributes defined at the object master level

Figure 8–7 shows how the attribute_value record is related to other records.

Figure 8–7: Relationships of attribute value records to other records

In this illustration, you can see that the SmartObject relationship is defined for the attribute_value because it is a value for a particular SmartObject. Because this is the master for the object, there is no instance or container relationship.

Attribute values defined at the object instance level

When the framework creates attributes for an object instance, it populates the object_type_obj and the smartobject_obj fields, and also sets the object_instance_obj field to point to the ryc_object_instance record that defines the instance, as well as the container_smartobject_obj field, which points to the container’s ryc_smartobject record.

To illustrate this case, we can extend the second example to show another attribute of the same dynamic viewer. In this case, we pick an attribute that can be changed at the instance level, such as DisableOnInit. You can change this from its default value of No to Yes in the dynamic property sheet, as shown in Figure 8–8.

Figure 8–8: Attributes defined at the object instance level

If you do this in the Container Builder, when you are building a window such as the oemaintwin example, you are changing the attribute value just for that single instance of the viewer, as used in that window. The framework creates an attribute_value record to represent this overridden value and connects it to the object type, the viewer SmartObject, the object instance record for the viewer instance, and the SmartObject record for the container window.

Figure 8–9 shows the relationships for the instance attribute_value.

Figure 8–9: Instance attribute value relationships

The container_smartobject_obj points to the SmartObject for the window, and the object_instance_obj points to the instance of the viewer created for this window. When you place the viewer into the window in the Container Builder, you are creating an object_instance for it, which can have its own instance name and its own attribute values, as shown in Figure 8–10.

Figure 8–10: Object instances in the container builder window

All of this means that there are several different combinations of object ID pointers that framework code must check for to determine the level of an attribute value and what object it is defined for. To assist in this, another object ID field holds the meaningful identifier for the value, so that code can look at a single field to determine what the significant key is. This field is called the primary_smartobject_obj. This field contains the value of the container_smartobject_obj if that is not 0; otherwise the smartobject_obj if that is not 0; otherwise 0. It is used as the replication key field when writing replication triggers to cascade changes to the version database, as the replication triggers could not handle the use of alternative fields (for example, container_smartobject_obj or smartobject_obj). The update of this field is done in the write trigger for the table.

Note: Be careful when looking for attributes associated with an object_type. Make sure that you look for the specific object_type and 0 values for the SmartObject and object_instance object ID fields.

This might all sound complicated, but the rules that determine which fields are used are fairly straightforward. We can summarize all this with some code samples in the following sections.

Code examples for an attribute value at the class level

If an attribute value is defined for an object type or class, then the object_type_obj is defined and points to the object_type record. The other object IDs, for SmartObject, instance, and container, are not defined (therefore 0), because the value is not associated with a specific object. You can determine all the default attribute values for a class by retrieving the attribute_value records for which smartobject_obj, object_instance_obj, and container_smartobject_obj are all 0.

The next example shows a simple code block that locates all the object type records for the NavigationSourceEvents attribute. The code retrieves only records where the smartobject_obj is 0. (If this is the case, then object_instance_obj and container_smartobject_obj are also 0.) This locates the attribute values defined at the class level, as shown:

FOR EACH ryc_attribute_value WHERE  
    attribute_label = 'NavigationSourceEvents' AND smartobject_obj = 0: 
        FIND gsc_object_type OF ryc_attribute_value. 
        DISPLAY object_type_code character_value FORMAT "x(40)". 
END. 

This result in Figure 8–11 shows that there are two classes that define this attribute.

Figure 8–11: Class level attribute value

We have already discussed the Query class. The Container class uses this attribute because a container can be a pass-through object for a Navigation link coming in from outside the container. We can see that both classes define the same initial value for the attribute. Because it’s a CHARACTER attribute, the value is stored in the character_value field.

To confirm that this attribute does not change below the class level, you can leave out the WHERE clause qualifier AND smartobject_obj = 0. For example:

FOR EACH ryc_attribute_value WHERE  
    attribute_label = 'NavigationSourceEvents' /* AND smartobject_obj = 0 */ : 
        FIND gsc_object_type OF ryc_attribute_value. 
        DISPLAY object_type_code character_value FORMAT "x(40)". 
END. 

When you run this, the result is the same: only the two records show up. So, no master SmartObjects override this default value.

Code examples for an attribute value at the master level

If an attribute value is defined for an object master, then the significant pointer is the smartobject_obj, which joins the record to the SmartObject record for the master object. The object_type is also filled in the previous example.

Another simple code block illustrates this relationship. The code looks for any attribute_value for the MinHeight attribute that has a SmartObject object ID. These all join to a SmartObject master. We only want to see those values that are defined for the master and not for one of its instances, so we also include the qualifier object_instance_obj = 0. For example:

FOR EACH ryc_attribute_value WHERE attribute_label = 'MinHeight' 
  AND smartobject_obj NE 0 AND object_instance_obj = 0: 
    FIND ryc_smartobject OF ryc_attribute_value. 
    DISPLAY object_filename FORMAT "x(20)" decimal_value . 
END. 

This is the result of the request. Figure 8–12 shows the customerviewv viewer among the objects with an assigned MinHeight value.

Figure 8–12: Objects with assigned minimum height values

To find out which object types have a MinHeight defined for the class itself, look for object types where the smartobject_obj is equal to 0. For example:

FOR EACH ryc_attribute_value WHERE attribute_label = 'MinHeight' 
  AND smartobject_obj = 0: 
    FIND gsc_object_type OF ryc_attribute_value. 
    DISPLAY object_type_code FORMAT "x(20)" decimal_value. 
END. 

There are in fact a few classes that define an initial value for the MinHeight, as shown in Figure 8–13.

Figure 8–13: Classes with defined initial values for MinHeight

In this example, the default height for a dynamic browser is 6.67 rows. Because the browser is a resizable object, this value applies initially to all dynamic browsers, unless you set it otherwise for the master or for an instance of the master in a window. By contrast, the dynamic viewer class does not have a default for MinHeight, because the height of the viewer is always determined by the layout of the fields it contains.

Code example for an attribute value at the instance level

If an attribute value is defined for an object instance, then there are really three significant pointers. As for the master attribute, the smartobject_obj joins the attribute_value record to the master SmartObject. In addition, the object_instance_obj joins the record to the object_instance of the SmartObject it’s defined for. Because the instance is always defined in the context of a particular container, the container_smartobject_obj is also defined and points to the SmartObject record of the container window. Again, for completeness, the object_type_obj is also filled in.

The following code is an example of this relationship using the DisableOnInit attribute. This block of code locates all attribute_value records where the DisableOnInit attribute has been set to YES at the object_instance level.

The code follows the join to locate the master SmartObject record for the value. It also follows the join to the object_instance for the value, from which it displays the layout position. Then it follows the join to the SmartObject record for the container. Because there are two different SmartObjectss the attribute value joins to, the master and the container, the code needs a second buffer for the container, as shown:

DEFINE BUFFER container_smo FOR ryc_smartobject. 
FOR EACH ryc_attribute_value WHERE object_instance_obj NE 0 AND 
  attribute_label = 'DisableOnInit' AND logical_value = YES: 
    FIND ryc_smartobject OF ryc_attribute_value. 
    FIND ryc_object_instance OF ryc_attribute_value. 
    FIND container_smo WHERE container_smo.smartobject_obj = 
        ryc_attribute_value.container_smartobject_obj. 
    DISPLAY ryc_attribute_value.logical_value VIEW-AS FILL-IN 
            ryc_smartobject.object_filename FORMAT "x(20)" 
            container_smo.object_filename   FORMAT "x(20)" 
            ryc_object_instance.layout_position. 
END. 

When you run this block of code, you see the three viewers in the oemaintwin test window shown in Figure 8–14. These are all disabled on initialization. (Note that the OrderLine viewer and the Order viewer have the same layout position because they are on different pages.)

Figure 8–14: DisableOnInit properties for oemaintwin


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095